package com.share51.novel.service.impl;

import com.share51.novel.common.enums.ProxySiteEnums;
import com.share51.novel.common.parse.ParseHtml;
import com.share51.novel.config.http.HttpClientConfig;
import com.share51.novel.config.http.HttpProxy;
import com.share51.novel.config.http.ProxySite;
import com.share51.novel.config.http.ProxySiteConfig;
import com.share51.novel.service.HttpClientService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.HttpHostConnectException;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

/**
 * http请求操作类
 * @author gb
 */
@Slf4j
@Service("httpClientService")
public class HttpClientServiceImpl implements HttpClientService {

    private static final int STATUS_OK=200;

    private static final int STATUS_FORBIDDEN=403;

    @Resource
    private HttpClientConfig httpClientConfig;

    @Resource
    private ProxySiteConfig proxySiteConfig;

    @Override
    public String doGet(String url) throws IOException {
       return this.doGet(url,3);
    }

    private String doGet(String url,int retry) throws IOException {
        if (retry>=0){
            if (StringUtils.isBlank(url)){
                log.info("缺少必要的运行参数，要请求的url为空");
                throw new IllegalArgumentException("缺少必要的运行参数，要请求的url为空");
            }
            HttpGet get=new HttpGet(url);
            setHttpHeaders(get);
            get.setConfig(getConfig());
            CloseableHttpResponse response = null;
            try {
                response = httpClientConfig.getHttpClient(url).execute(get);
                return getEntity(response,null,url,retry);
            } catch (HttpHostConnectException e) {
                log.error("链接超时",e);
                // 切换代理
                this.changeProxy();
                // 重新请求
                return this.doGet(url,--retry);
            }

        }
        return null;
    }

    private String getEntity(CloseableHttpResponse response,String charSet,String url,int retry) throws IOException {
        if (response==null){
            return null;
        }
        try {
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode==STATUS_OK){
                if (StringUtils.isBlank(charSet)){
                    charSet="UTF-8";
                }
                return EntityUtils.toString(response.getEntity(),charSet);
            }else if (statusCode==STATUS_FORBIDDEN){
                log.error("请求处理出错了，用户没有权限获取页面，换代理ip");
                // 换代理ip
                this.changeProxy();
                // 重试 3次
                this.doGet(url,--retry);
            }else {
                log.error("爬虫出错了！，错误url:{},错误码：{}",url,statusCode);
                throw new RuntimeException("爬虫出错了！，错误url:"+url +",错误码："+statusCode);
            }
        } finally {
            response.close();
        }
        return null;
    }

    @Override
    public ByteArrayOutputStream downloadFile(String url) throws IOException {
       return this.downloadFile(url,3);
    }

    private ByteArrayOutputStream downloadFile(String url,int retry)throws IOException {
        if (retry>=0){
            if (StringUtils.isBlank(url)){
                log.info("缺少必要的运行参数，要请求的url为空");
                throw new IllegalArgumentException("缺少必要的运行参数，要请求的url为空");
            }
            HttpGet get=new HttpGet(url);
            setHttpHeaders(get);
            get.setConfig(getConfig());
            CloseableHttpResponse response=null;
            InputStream is = null;
            try {
                response = httpClientConfig.getHttpClient(url).execute(get);
                if (response==null){
                    return null;
                }
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                is = response.getEntity().getContent();
                IOUtils.copy(is, bos);
                return bos;
            } catch (HttpHostConnectException e) {
               log.debug("下载链接超时",e);
               return downloadFile(url,--retry);
            }finally {
                if (is!=null){
                    is.close();
                }
                if (response!=null){
                    response.close();
                }
            }
        }
        throw new IOException("文件下载失败，多次重试失败！");
    }

    @Override
    public void initProxy() throws IOException {
        if (!HTTP_PROXY.isInitializing()) {
            System.out.println("STATUS_OK = " + STATUS_OK);
            HTTP_PROXY.setInitializing(true);
            List<ProxySite> proxySite = proxySiteConfig.getSites();
            for (ProxySite site:proxySite) {
                String html = this.doGet(site.getUrl());
                log.debug("爬取到代理ip网站，准备解析网站。网站源码为：{}",html);
                List<HttpProxy> list = ParseHtml.parseProxySite(html, ProxySiteEnums.of(site.getCode()));
                PROXY_QUEUE.addAll(list);
                log.debug("将爬取到的代理加入代理池中");
            }
            HTTP_PROXY.setInitializing(false);
        }
    }

    @Override
    public boolean enableProxy() {
        return proxySiteConfig.isEnableProxy();
    }
}
